import time
from abc import abstractmethod, ABC
from urllib.parse import urlencode

import requests
from rest_framework.response import Response

from tools.myjwt import mytoken
from user import models, seruser


# 单例模式装饰器
def singleton(cls):
    """
    单例模式的装饰器函数，确保一个类只有一个实例

    Args:
        cls: 类本身

    Returns:
        get_instance: 返回类的实例
    """
    instances = {}

    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance


# 定义社交登录抽象类
class sfLogin(ABC):
    """
    抽象类sfLogin，用于定义社交登录接口
    """

    @abstractmethod
    def get_url(self):
        """
        抽象方法get_url，用于获取登录URL
        """
        pass

    @abstractmethod
    def roll_bcak(self):
        """
        抽象方法roll_bcak，用于处理登录回调
        """
        pass


# 钉钉登录类
class DingDing(sfLogin):
    """
    DingDing类继承sfLogin，实现钉钉登录功能
    """
    _instance = None

    def __new__(cls):
        """
        实现单例模式的构造方法

        Returns:
            cls._instance: 返回钉钉登录类的实例
        """
        if cls._instance is None:
            cls._instance = super(DingDing, cls).__new__(cls)
        return cls._instance

    def get_url(self):
        """
        实现获取钉钉登录URL的方法

        Returns:
            url: 返回构造好的钉钉登录URL
        """
        prompts = {
            'redirect_uri': 'http://127.0.0.1:5173/login',
            'response_type': 'code',
            'client_id': 'dingwatcx6xlh7ec0kgt',
            'scope': 'openid corpid',
            'prompt': 'consent'
        }
        url = "https://login.dingtalk.com/oauth2/auth?" + urlencode(prompts)
        return url

    def roll_bcak(self, request):
        """
        实现钉钉登录回调方法

        Args:
            request: 请求对象，包含回调时的查询参数

        Returns:
            query: 包含用户信息和token的查询字符串列表
        """
        authCode = request.query_params.get('code')
        print(authCode)
        prompts = {
            "clientId": "dingwatcx6xlh7ec0kgt",
            "clientSecret": "orUkc9tg_abtAxEDMaRx5ZkcbNUeAsvucdbq0yqJor8_ViYzb-tUCuKL11-L4R02",
            "code": authCode,
            "grantType": "authorization_code"
        }
        # response_headers = {
        #     'Content-Type': 'application/x-www-form-urlencoded'
        # }
        response_url = 'https://api.dingtalk.com/v1.0/oauth2/userAccessToken'
        response = requests.post(response_url, json=prompts).json()
        accessToken = response.get('accessToken')
        refreshToken = response.get('refreshToken')
        print(response)
        print(accessToken)
        res_url = 'https://api.dingtalk.com/v1.0/contact/users/me'
        res_headers = {"x-acs-dingtalk-access-token": accessToken}
        resp = requests.get(res_url, headers=res_headers).json()
        print(resp)
        name = resp.get('nick')
        uid = resp.get('openId')
        phone = resp.get('mobile')
        # 登录，写入三方登录表和用户表
        sfl = models.UserLogin.objects.filter(uid=uid, login_type_id=1).first()
        if not sfl:
            # 写入用户表
            user1, created = models.Users.objects.get_or_create(phone=phone, defaults={'name': name})
            
            # 写入三方登录表
            userid = user1.id
            user = user1  # 直接使用已创建的user对象
            print('------------------------------------------------------------------------')
            print(userid)
            sfinfo = {
                "login_type_id": 1,
                "uid": uid,
                "token": accessToken,
                "retoken": refreshToken,
                "user_id": userid
            }
            models.UserLogin.objects.create(**sfinfo)
            models.Users.objects.filter(id=user.id).update(name=name)  # 更新用户信息
        else:
            user = sfl.user
            userid = user.id  # 添加这行确保现有用户也能获取userid
            sfl.token = accessToken
            sfl.save()

        # 生成jwt token并返回前端
        payload = {"userid": userid, "userphone": user.phone, "exp": int(time.time()) + 60 * 60 * 2}
        token = mytoken.settoken(payload)
        payload["exp"] = int(time.time() + 60 * 60 * 3)
        retoken = mytoken.settoken(payload)
        query = {
            'userid': userid,
            'token': token,
            'retoken': retoken
        }
        return query


# 工厂类，用于创建不同类型的登录实例
class Factory:
    """
    Factory类用于根据类型创建对应的登录实例
    """

    def create_login(self, types):
        """
        根据类型创建登录实例的方法

        Args:
            types: 登录类型，如"dingding"

        Returns:
            登录实例或抛出不支持的登录类型异常
        """
        if types == "dingding":
            return DingDing()
        else:
            raise ValueError(f"Unsupported login type: template")


# 创建Factory实例
f = Factory()
